var $ = require('jquery')
var yo = require('yo-yo')
var remixLib = require('remix-lib')
var EventManager = remixLib.EventManager
var css = require('../styles/run-tab-styles')
var copyToClipboard = require('../../ui/copy-to-clipboard')
var modalDialogCustom = require('../../ui/modal-dialog-custom')
var addTooltip = require('../../ui/tooltip')
var helper = require('../../../lib/helper.js')

class SettingsUI {

  constructor (settings) {
    this.settings = settings
    this.event = new EventManager()

    this.settings.event.register('transactionExecuted', (error, from, to, data, lookupOnly, txResult) => {
      if (error) return
      if (!lookupOnly) this.el.querySelector('#value').value = '0'
      this.updateAccountBalances()
    })

    setInterval(() => {
      this.updateAccountBalances()
    }, 10 * 1000)

    this.accountListCallId = 0
    this.loadedAccounts = {}
  }

  updateAccountBalances () {
    if (!this.el) return
    var accounts = $(this.el.querySelector('#txorigin')).children('option')
    accounts.each((index, account) => {
      this.settings.getAccountBalanceForAddress(account.value, (err, balance) => {
        if (err) return
        account.innerText = helper.shortenAddress(account.value, balance)
      })
    })
  }

  render () {
    this.netUI = yo`<span class=${css.network}></span>`

    var environmentEl = yo`
      <div class="${css.crow}">
        <div id="selectExEnv" class="${css.col1_1}">
          节点环境
        </div>
        <div class=${css.environment}>
          ${this.netUI}
          <select id="selectExEnvOptions" onchange=${() => { this.updateNetwork() }} class="${css.select}">
            <option id="vm-mode"
              title="JavaScript虚拟机不会连接任何节点，所有数据都在本地和内存中"
              value="vm" checked name="executionContext"> JavaScript虚拟机
            </option>
            <option id="injected-mode"
              title="使用Metamask或类似提供器注入的Web3对象"
              value="injected" checked name="executionContext">注入的Web3对象
            </option>
            <option id="web3-mode"
              title="连接到本机或其他节点，交易将发送到网络中，可能会造成资金损失！"
              value="web3" name="executionContext"> Web3提供器
            </option>
          </select>
          <a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md" target="_blank"><i class="${css.icon} fa fa-info"></i></a>
        </div>
      </div>
    `

    var accountEl = yo`
      <div class="${css.crow}">
        <div class="${css.col1_1}">
          当前账号
          <i class="fa fa-plus-circle ${css.icon}" aria-hidden="true" onclick=${this.newAccount.bind(this)} title="创建一个新账号"></i>
        </div>
        <div class=${css.account}>
          <select name="txorigin" class="${css.select}" id="txorigin"></select>
          ${copyToClipboard(() => document.querySelector('#runTabView #txorigin').value)}
          <i class="fa fa-pencil-square-o ${css.icon}" aria-hiden="true" onclick=${this.signMessage.bind(this)} title="使用这个账号的密钥对交易签名"></i>
        </div>
      </div>
    `

    var gasPriceEl = yo`
      <div class="${css.crow}">
        <div class="${css.col1_1}">Gas上限</div>
        <input type="number" class="${css.col2}" id="gasLimit" value="3000000">
      </div>
    `

    var valueEl = yo`
      <div class="${css.crow}">
        <div class="${css.col1_1}">交易金额</div>
        <input type="text" class="${css.col2_1}" id="value" value="0" title="输入数值并选择计量单位">
        <select name="unit" class="${css.col2_2}" id="unit">
          <option data-unit="wei">wei</option>
          <option data-unit="gwei">gwei</option>
          <option data-unit="finney">finney</option>
          <option data-unit="ether">ether</option>
        </select>
      </div>
    `

    var el = yo`
      <div class="${css.settings}">
        ${environmentEl}
        ${accountEl}
        ${gasPriceEl}
        ${valueEl}
      </div>
    `

    var selectExEnv = environmentEl.querySelector('#selectExEnvOptions')
    this.setDropdown(selectExEnv)

    this.settings.event.register('contextChanged', (context, silent) => {
      this.setFinalContext()
    })

    setInterval(() => {
      this.updateNetwork()
      this.fillAccountsList()
    }, 5000)

    this.el = el
    return el
  }

  setDropdown (selectExEnv) {
    this.selectExEnv = selectExEnv

    this.settings.event.register('addProvider', (network) => {
      selectExEnv.appendChild(yo`<option
              title="Manually added environment: ${network.url}"
              value="${network.name}" name="executionContext"> ${network.name}
            </option>`)
      addTooltip(`${network.name} [${network.url}] added`)
    })

    this.settings.event.register('removeProvider', (name) => {
      var env = selectExEnv.querySelector(`option[value="${name}"]`)
      if (env) {
        selectExEnv.removeChild(env)
        addTooltip(`${name} removed`)
      }
    })

    selectExEnv.addEventListener('change', (event) => {
      let context = selectExEnv.options[selectExEnv.selectedIndex].value
      this.settings.changeExecutionContext(context, () => {
        modalDialogCustom.confirm(null, '你确定要连接到外部以太坊节点吗？', () => {
          modalDialogCustom.prompt(null, 'Web3 Provider Endpoint', 'http://localhost:8545', (target) => {
            this.settings.setProviderFromEndpoint(target, context, (alertMsg) => {
              if (alertMsg) {
                modalDialogCustom.alert(alertMsg)
              }
              this.setFinalContext()
            })
          }, this.setFinalContext.bind(this))
        }, this.setFinalContext.bind(this))
      }, (alertMsg) => {
        modalDialogCustom.alert(alertMsg)
      }, this.setFinalContext.bind(this))
    })

    selectExEnv.value = this.settings.getProvider()
  }

  setFinalContext () {
    // set the final context. Cause it is possible that this is not the one we've originaly selected
    this.selectExEnv.value = this.settings.getProvider()
    this.event.trigger('clearInstance', [])
    this.updateNetwork()
    this.fillAccountsList()
  }

  newAccount () {
    this.settings.newAccount(
      (cb) => {
        modalDialogCustom.promptPassphraseCreation((error, passphrase) => {
          if (error) {
            return modalDialogCustom.alert(error)
          }
          cb(passphrase)
        }, () => {})
      },
      (error, address) => {
        if (error) {
          return addTooltip('Cannot create an account: ' + error)
        }
        addTooltip(`account ${address} created`)
      }
    )
  }

  signMessage () {
    this.settings.getAccounts((err, accounts) => {
      if (err) {
        return addTooltip(`Cannot get account list: ${err}`)
      }

      var signMessageDialog = { 'title': 'Sign a message', 'text': 'Enter a message to sign', 'inputvalue': 'Message to sign' }
      var $txOrigin = this.el.querySelector('#txorigin')
      var account = $txOrigin.selectedOptions[0].value

      var promptCb = (passphrase) => {
        modalDialogCustom.promptMulti(signMessageDialog, (message) => {
          this.settings.signMessage(message, account, passphrase, (err, msgHash, signedData) => {
            if (err) {
              return addTooltip(err)
            }
            modalDialogCustom.alert(yo`<div><b>hash:</b>${msgHash}<br><b>signature:</b>${signedData}</div>`)
          })
        }, false)
      }

      if (this.settings.isWeb3Provider()) {
        return modalDialogCustom.promptPassphrase('Passphrase to sign a message', 'Enter your passphrase for this account to sign the message', '', promptCb, false)
      }
      promptCb()
    })
  }

  updateNetwork () {
    this.settings.updateNetwork((err, {id, name} = {}) => {
      if (err) {
        this.netUI.innerHTML = 'can\'t detect network '
        return
      }
      this.netUI.innerHTML = `<i class="${css.networkItem} fa fa-plug" aria-hidden="true"></i> ${name} (${id || '-'})`
    })
  }

  // TODO: unclear what's the goal of accountListCallId, feels like it can be simplified
  fillAccountsList () {
    this.accountListCallId++
    var callid = this.accountListCallId
    var txOrigin = this.el.querySelector('#txorigin')
    this.settings.getAccounts((err, accounts) => {
      if (this.accountListCallId > callid) return
      this.accountListCallId++
      if (err) { addTooltip(`Cannot get account list: ${err}`) }
      for (var loadedaddress in this.loadedAccounts) {
        if (accounts.indexOf(loadedaddress) === -1) {
          txOrigin.removeChild(txOrigin.querySelector('option[value="' + loadedaddress + '"]'))
          delete this.loadedAccounts[loadedaddress]
        }
      }
      for (var i in accounts) {
        var address = accounts[i]
        if (!this.loadedAccounts[address]) {
          txOrigin.appendChild(yo`<option value="${address}" >${address}</option>`)
          this.loadedAccounts[address] = 1
        }
      }
      txOrigin.setAttribute('value', accounts[0])
    })
  }

}

module.exports = SettingsUI
